#pragma once
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include "error.hpp"
#include "log.hpp"

class Sock
{
public:
    const int backlog = 12;
    void Socket()
    {
        socket_ = socket(AF_INET, SOCK_STREAM, 0);
        if (socket_ < 0)
        {
            log_(ErrorLevel::Fatal, "create socket error:%d :%s ", errno, strerror(errno));
            exit(SOCKET_ERR);
        }
    }
    //输入const&
    //输出*
    //输入输出&
     void Bind(const uint16_t& port)
    {
        // 绑定端口号和ip地址
        struct sockaddr_in sock;
        bzero(&sock, sizeof(sock));
        sock.sin_addr.s_addr = INADDR_ANY; //设置ip地址 表示所有的ip的地址
        sock.sin_port = htons(port);
        sock.sin_family = AF_INET;
        if (bind(socket_, (sockaddr *)(&sock), sizeof(sock)) < 0)
        {
            log_(ErrorLevel::Fatal, "bind error:%d errstring:%s ", errno, strerror(errno));
            exit(BIND_ERR);
        }
    }
    void Listen()
    {
        // 开始监听
        if (listen(socket_, backlog)) // 返回0,监听成功
        {
            log_(ErrorLevel::Fatal, "listen err");
            exit(LISTEN_ERR);
        }
    }
    int Connect(const string &ip,const u_int16_t& port)
    {
        struct sockaddr_in sock;
        sock.sin_addr.s_addr = inet_addr(ip.c_str());
        sock.sin_port = htons(port);
        sock.sin_family = AF_INET;
        int len = sizeof(sock);
        // 开始连接
        int timenum = 5;
        return connect(socket_, (sockaddr *)&sock, len);//由外部控制重连
        // int timenum = 5;
        // while (connect(socket_, (sockaddr *)&sock, len) < 0)
        // {
        //     sleep(1);
        //     std::cout << "开始重连:" << std::endl;
        //     timenum--;
        //     if (timenum == 0)
        //         break;
        // }
    }
    int Accept(string* ip,uint16_t* port) // 名字不能为accept
    {
        // 获取链接
        struct sockaddr_in sock; // 头文件<netinet/in.h>
        bzero(&sock, sizeof(sock));
        socklen_t len = sizeof(sock);
        int socket = accept(socket_, (sockaddr *)&sock, &len);
        if (socket < 0)
        {
            log_(ErrorLevel::Info, "accept err");
            exit(SOCKET_ERR);
        }
        else
        {
            *ip = inet_ntoa(sock.sin_addr);
            *port = ntohs(sock.sin_port);
        }
        return socket;
    }
    ~Sock()
    {
        close(socket_);
    }
    int socket_;
    Log log_;
};